﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WooCoo.Tools;

namespace WooCoo.ObjectModel.ManagedProperty
{
    /// <summary>
    /// 属性值元数据管理器,每个被托管类都有一个实例。
    /// 由于会在端传输，因此需要支持序列化
    /// </summary>
    [Serializable]
    public sealed class FieldDataManager
    {
        /// <summary>
        /// 所属的托管类
        /// </summary>
        [NonSerialized]
        private ManagedPropertyBase _owner;

        //[NonSerialized()]
        //private List<IPropertyInfo> _propertyList;
        /// <summary>
        /// 编译期
        /// </summary>
        private IFieldData[] _fieldDatas;
        /// <summary>
        /// 运行期，对两类属性进行区分管理
        /// </summary>
        //internal Dictionary<IPropertyInfo, IFieldData> _runtimeFields;

        private FieldDataManager()
        { }

        internal FieldDataManager(ManagedPropertyBase entity)
        {
            this._owner = entity;
            this.InitFields();
        }

        private void InitFields()
        {
            var compiledFieldsCount = this._owner.Properties.GetProperties().Count();

            this._fieldDatas = new IFieldData[compiledFieldsCount];
        }

        /// <summary>
        /// 获取指定属性的关联<see cref="IFieldData" /> 对象
        /// for a specific field.
        /// </summary>
        /// <param name="propertyInfo">
        /// 指向字段的属性对象.
        /// </param>
        [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Advanced)]
        public IFieldData GetFieldData(IPropertyInfo propertyInfo)
        {
            try
            {
                return this._fieldDatas[propertyInfo.Index];
            }
            catch (IndexOutOfRangeException ex)
            {
                throw new InvalidOperationException(string.Format(Localizer.Active.GetLocalizeString(StringID.PropertyNotRegistered), propertyInfo.Name), ex);
            }
        }

        private IFieldData GetOrCreateFieldData(IPropertyInfo property)
        {
            try
            {
                var field = _fieldDatas[property.Index];
                if (field == null)
                {
                    field = property.CreateFieldData(property.Name);
                    _fieldDatas[property.Index] = field;
                }
                return field;
            }
            catch (IndexOutOfRangeException ex)
            {
                throw new InvalidOperationException(string.Format("属性:{0}还未注册 ", property.Name), ex);
            }
        }

        #region GetProperty
        /// <summary>
        /// 取得指定属性的值
        /// </summary>
        /// <param name="property"></param>
        /// <returns></returns>
        internal object GetProperty(IPropertyInfo property)
        {
            object result = null;
            var field = this._fieldDatas[property.Index];
            if (field != null)
                result = field.Value;
            result = result ?? property.DefaultValue;
            return result;
        }
        /// <summary>
        /// 取得指定属性的值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="property"></param>
        /// <returns></returns>
        internal T GetProperty<T>(PropertyInfo<T> property)
        {
            var result = default(T);
            var field = this._fieldDatas[property.Index];
            if (field != null)
                result = (field as FieldData<T>).Value;
            return result;
        }
        #endregion

        #region SetProperty
        /// <summary>
        /// 设置属性值
        /// </summary>
        /// <param name="property"></param>
        /// <param name="value"></param>
        /// <returns>值变更返回True,否则返回False</returns>
        internal bool SetProperty(IPropertyInfo property, object value)
        {
            bool doChange = true;
            Type valueType;
            if (value != null)
                valueType = value.GetType();
            else
                valueType = property.Type;

            value = TypeHelper.CoerceValue(property.Type, valueType, value);
            var field = GetOrCreateFieldData(property);

            var oldValue = field.Value;
            if (oldValue == null) { oldValue = property.DefaultValue; }

            if (object.Equals(oldValue, value))
            {
                doChange = false;
            }
            else
            {
                field.Value = value;
                //field.IsDirty = true;
            }
            return doChange;
        }
        /// <summary>
        /// 设置属性值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="property"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        internal bool SetProperty<T>(PropertyInfo<T> property, T value)
        {
            bool doChange = true;
            var field = GetOrCreateFieldData(property);
            var oldValue = field.Value ?? default(T);

            var fd = field as IFieldData<T>;
            if (object.Equals(oldValue, value))
            {
                doChange = false;
            }
            else
            {
                field.Value = value;
                //field.IsDirty = true;
            }
            return doChange;
        }

        #endregion

        #region LoadProperty
        /// <summary>
        /// 载入指定的属性，该方法一般为延迟加载对象的get;set;属性中应用 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="property"></param>
        /// <param name="value"></param>
        internal void LoadProperty<T>(PropertyInfo<T> property, T value)
        {
            var field = GetOrCreateFieldData(property);
            field.Value = value;
            field.MarkClean();
        }

        internal void LoadProperty(IPropertyInfo property, object value)
        {
            var field = GetOrCreateFieldData(property);
            field.Value = value;
            field.MarkClean();
        }
        #endregion

        #region Field代理
        /// <summary>
        /// 取得值改变的字段
        /// </summary>
        /// <returns></returns>
        public IEnumerable<IFieldData> GetDirtyFieldDatas()
        {
            foreach (var field in this._fieldDatas)
            {
                if (field != null)
                {
                    if (field.Value is ITrackStatus && (field.Value as ITrackStatus).IsDirty)
                        yield return field;
                    else if (field.IsDirty)
                        yield return field;
                }
            }
        }

        public IEnumerable<IFieldData> GetChildEntity()
        {
            foreach (var field in this._fieldDatas)
            {
                if (field != null)
                {
                    if (field.Value is IEntityList)
                        yield return field;                    
                }
            }
        }
        /// <summary>
        /// 返回是否存在字段脏标识        
        /// </summary>
        public bool IsDirty()
        {
            foreach (var item in this._fieldDatas)
                if (item != null && item.IsDirty)
                    return true;
            return false;
        }

        /// <summary>
        /// Marks all fields as clean
        /// (not dirty).
        /// </summary>
        internal void MarkClean()
        {
            foreach (var item in this._fieldDatas)
                if (item != null && item.IsDirty)
                    item.MarkClean();
        }

        internal bool FieldExists(IPropertyInfo property)
        {
            try
            {
                return this._fieldDatas[property.Index] != null;
            }
            catch (IndexOutOfRangeException ex)
            {
                throw new InvalidOperationException();
            }
        }
        #endregion
    }
}
